﻿using Common.Contract;
using Common.Contract.Authentication.Record;
using Common.Contract.Customer;
using Common.Contract.Customer.Record;
using Common.Contract.Customer.Request;
using Common.Contract.Paging;
using Common.Contract.SaleOut;
using Common.Contract.SaleOut.Request;
using Common.Contract.Warranty.Request;
using Common.Contract.Warranty.Response;
using Common.Service;
using Common.Service.Command;
using Common.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Warranty.Model.Interface;
using Warranty.Model.Model;

namespace Warranty.ServiceCommand
{
    public class SearchSerialChasingServiceCommand : ProviderServiceCommand<IProviderFactory, SearchSerialChasingRequest, SearchSerialChasingResponse>
    {
        public SearchSerialChasingServiceCommand(IProviderFactory provider) : base(provider) { }

        protected override void Validate(SearchSerialChasingRequest request)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (!request.Header.ApplicationKey.HasValue || request.Header.ApplicationKey == Guid.Empty)
            {
                throw new ArgumentException("ApplicationKey must be set", "request");
            }
        }

        protected override bool OnExecute(SearchSerialChasingResponse response)
        {
            bool isSuccess = true;
            string errorMessage = string.Empty;
            int pageSize = 0, pageIndex = 0, totalRecord = 0;
            List<SerialChasingRecord> records = new List<SerialChasingRecord>();

            #region Path1 - PROD
            // Get max SinpLog
            var addLogs = Providers.AddWMSinpLogs.SearchAddWMSinpLogs(Request.SerialNumber);
            var actualTimeMax = addLogs.Max(x => x.Actualtime);
            if (!actualTimeMax.IsNullOrWhiteSpace())
                addLogs = addLogs.Where(x => x.Actualtime == actualTimeMax).ToList();

            var products = addLogs.Select(x => new Product
            {
                BoxNo = x.LotBox,
                SerialNo = x.LotSet ?? x.LotBox,
                ProductModel = x.Model,
                Suffix = x.Suffix,
                WorkOrder = x.WorkOrder,
                ProductDate = x.Actualtime.ToDateTime("yyyyMMdd")
            }).ToList();

            //Get list from serialNoPrinted
            var serialNoPrinteds = Providers.SerialNoPrinted.SerialNoPrinted(Request.SerialNumber, "DISPLAY_SET");
            var workOrders = Providers.WorkOrders.SearchWorkOrders();
            var query = from a in serialNoPrinteds
                        join c in workOrders on a.WorkOrder equals c.Work_Order
                        select new Product
                        {
                            BoxNo = a.SerialNo,
                            SerialNo = a.SerialNo,
                            ProductModel = c.PartNo,
                            Suffix = c.PartNo,
                            WorkOrder = a.WorkOrder,
                            ProductDate = c.ScheduledCompletionDate
                        };
            var products2 = query.Distinct().ToList();

            var product3 = Providers.CbuHistIf.SearchCbuHistIf(Request.SerialNumber).Select(x => new Product
                        {
                            BoxNo = x.LotBox,
                            SerialNo = x.LotSet,
                            ProductModel = x.ModelCode,
                            Suffix = x.Suffix,
                            WorkOrder = x.LotId,
                            ProductDate = x.TransferDate
                        }).ToList();
            products.AddRange(products2);
            products.AddRange(product3);
            #endregion

            #region Path2 - SaleIn
            var o1 = Providers.OrderShipHist.SearchOrderShipHist();
            List<OrderInf> si = new List<OrderInf>();
            using (ServiceClient<ISaleOut> serviceClient = new ServiceClient<ISaleOut>())
            {
                SearchCdcHistRequest request = new SearchCdcHistRequest
                {
                    Header = null,
                    Model = Request.Model,
                    SerialNo = Request.SerialNumber
                };
                var c = serviceClient.Proxy.SearchCdcHistory(request);
                if (c.IsSuccess)
                {
                    var query1 = from oitem in o1
                                 join citem in c.Records on oitem.OrderNo equals citem.OrderNumber
                                 into items_joined1
                                 from item_joined in items_joined1.DefaultIfEmpty()
                                 from school in items_joined1.Where(v => item_joined == null ? false : (v.Model == oitem.Model || v.InvOrg == oitem.InvOrg)).DefaultIfEmpty()
                                 select (new OrderInf
                                     {
                                         BilltoName = oitem.BilltoName,
                                         InventoryOrg = oitem.InvOrg,
                                         Model = oitem.Model,
                                         OrderNumber = oitem.OrderNo,
                                         SellinDate = oitem.RequestArrivalDate,
                                         SerialNumber = school.SerialNo,
                                         ShiptoName = oitem.ShiptoName,
                                         Suffix = oitem.Suffix
                                     });
                    var item1 = query1.ToList();
                    si.AddRange(item1);
                }

                SearchRdcHistRequest requestRdc = new SearchRdcHistRequest
                {
                    Header = null,
                    Model = Request.Model,
                    SerialNo = Request.SerialNumber
                };
                var r = serviceClient.Proxy.SearchRdcHistory(requestRdc);
                if (r.IsSuccess)
                {
                    var query2 = from oitem in o1
                                 join citem in r.Records on oitem.Model equals citem.Model
                                 into items_joined1
                                 from item_joined in items_joined1.DefaultIfEmpty()
                                 from school in items_joined1.Where(v => item_joined == null ? false : (v.ShipNumber == oitem.OrderNo || v.EDINumber == oitem.PickNo || v.InventoryOrganization == oitem.InvOrg)).DefaultIfEmpty()
                                 select (new OrderInf
                                 {
                                     BilltoName = oitem.BilltoName,
                                     InventoryOrg = oitem.InvOrg,
                                     Model = oitem.Model,
                                     OrderNumber = oitem.OrderNo,
                                     SellinDate = oitem.RequestArrivalDate,
                                     SerialNumber = school.SerialNumber,
                                     ShiptoName = oitem.ShiptoName,
                                     Suffix = oitem.Suffix
                                 });
                    var item2 = query2.ToList();
                    si.AddRange(item2);
                }
            }
            #endregion

            #region Serial chasing response
            var result = from si_item in si
                         join p_item in products on si_item.SerialNumber equals p_item.SerialNo
                         into items_joined
                         from item_joined in items_joined.DefaultIfEmpty()
                         select (new SerialChasingRecord
                         {
                             SerialNumber = item_joined.SerialNo,
                             BoxNo = item_joined.BoxNo,
                             SaleSuffix = si_item.Suffix,
                             SaleModel = si_item.Model,
                             OrderNumber = si_item.OrderNumber,
                             SellinDate = si_item.SellinDate,
                             ProductModel = item_joined.ProductModel,
                             ProductSuffix = item_joined.Suffix,
                             ProductDate = item_joined.ProductDate
                         });
            records = result.ToList();
            totalRecord = records.Count;
            if (pageSize > 0 && pageIndex >= 0)
            {
                records = records.Skip(pageIndex * pageSize).Take(pageSize).ToList();
            }
            #endregion

            response.Records = records;
            response.Page = new PageRecord
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                TotalRecords = totalRecord
            };
            return isSuccess;
        }


        private class Product
        {
            public string SerialNo { get; set; }
            public string BoxNo { get; set; }
            public string ProductModel { get; set; }
            public string Suffix { get; set; }
            public string WorkOrder { get; set; }
            public DateTime? ProductDate { get; set; }
        }

        private class OrderInf
        {
            public string InventoryOrg { get; set; }
            public string BilltoName { get; set; }
            public string ShiptoName { get; set; }
            public string OrderNumber { get; set; }
            public string Model { get; set; }
            public string Suffix { get; set; }
            public string SerialNumber { get; set; }
            public DateTime? SellinDate { get; set; }
        }
    }
}

//  SELECT   DECODE(prod.serial_no, null, si.serial_no, prod.serial_no)
//                                             SERIAL_NO
//        ,prod.box_no                         BOX_NO                                                              
//        ,prod.prod_model                     PROD_MODEL
//        ,prod.prod_suffix                    PROD_SUFFIX
//        ,si.model                            SAL_MODEL
//        ,si.suffix                           SAL_SUFFIX
//        ,si.order_no                         ORDER_NO
//        ,prod.prod_date                      PRODUCT_DATE
//        ,si.sellin_date                      SELLIN_DATE
//  FROM  (
//         SELECT DISTINCT(serial_no)          SERIAL_NO
//               ,box_no                       BOX_NO
//               ,prod_model                   PROD_MODEL
//               ,prod_suffix                  PROD_SUFFIX
//               ,work_order                   WORK_ORDER
//               ,TO_CHAR(prod_date,'YYYY-MM-DD')                    
//                                             PROD_DATE 
//         FROM (   PROD
//       ,(

//         SELECT o1.inv_org                   INV_ORG
//               ,o1.billto_name               BILLTO_NAME
//               ,o1.shipto_name               SHIPTO_NAME
//               ,o1.order_no                  ORDER_NO
//               ,o1.model                     MODEL
//               ,o1.suffix                    SUFFIX
//               ,c.serial_no                  SERIAL_NO 
//               ,TO_CHAR(o1.request_arrival_date,'YYYY-MM-DD')      
//                                             SELLIN_DATE           
//         FROM   tb_sn_cdc_hist               C
//               ,tb_order_ship_hist           O1
//         WHERE  c.inv_org                  = o1.inv_org(+)
//         AND    c.order_no                 = o1.order_no(+)
//         AND    c.model                    = o1.model(+)
//         AND    c.serial_no             LIKE UPPER(p_serial_no)
//         AND    c.model                 LIKE DECODE(p_model, null, '%', UPPER(p_model))  

//     UNION
//         SELECT o.inv_org                    INV_ORG
//               ,o.billto_name                BILLTO_NAME
//               ,o.shipto_name                SHIPTO_NAME
//               ,o.order_no                   ORDER_NO
//               ,o.model                      MODEL 
//               ,o.suffix                     SUFFIX
//               ,r.serial_no                  SERIAL_NO 
//               ,TO_CHAR(o.request_arrival_date,'YYYY-MM-DD')       
//                                             SELLIN_DATE
//         FROM   tb_sn_rdc_hist               R
//               ,tb_order_ship_hist           O
//         WHERE  r.inv_org                  = o.inv_org(+) 
//         --AND    r.edi_no                   = o.pick_no(+)
//         AND   (r.ship_no                  = o.order_no OR r.edi_no  = o.pick_no)   
//         AND    r.model                    = o.model(+)
//         AND    r.serial_no             LIKE UPPER(p_serial_no)
//         AND    r.model                 LIKE DECODE(p_model, null, '%', UPPER(p_model)))
//                                             SI     
//WHERE    si.serial_no                     = prod.serial_no(+);